<?php
/**
 * @author Jelle Heemskerk <riverburn@gmail.com>, Niek Saarberg <n.saarberg@gmail.com>
 * @version 0.0.2
 * @package Router
 * @date March 12, 2009
 *
 * Todo:
 * -
 *
 * Changes:
 * 0.0.7
 * - Niek S. Changed is_int check to is_numeric in ::delete()
 * 0.0.7
 * - Rick S. Added ::read_all_with_relations()
 * 0.0.6
 * - Niek S. Added ::primary_key(), ::extend_relations()
 * 0.0.5
 * - Niek S. Added ::read_all_where(), bridge to DBH::read_all_where()
 * 0.0.4
 * - Niek S. ::create(), now fetches relations if there are eny
 * 0.0.3
 * - Niek S. Added relations to create
 * 0.0.2
 * - Niek S. Added CRUD ( Create, Read, Update and Delete ) functions
 * 0.0.1
 * - Niek S. Class created and added created base functionality
 * - ::__construct(), abstract
 */

/**
 * Note to self
 * Only within the controller, relations are avaible
 */
abstract class Controller {

	protected $registry;

	public function __construct(&$registry) {

		$this->registry 			= $registry;
		$this->view 				= &$this->registry->view;
		$this->get					= &$this->registry->router->route['parameter'];
		$this->router_action		= &$this->registry->router->route['action'];
		$this->router_controller	= &$this->registry->router->route['controller'];

		// Execute controller settings
		if(method_exists($this, 'initialize')) {
			$this->initialize();
		}
	}

	abstract function indexAction();

	/**
	 * Create a row in the database
	 * If there are any relations they will be saved
	 *
	 * @param object $object
	 * @return int inserted row id
	 */
	public function create ( $object ) {

		if( isset( $this->table ) == false ) {
				
			log::fatal( 'Table name not found', $this, 'create()' );
		}

		// If no relations are set, then query object immediately
		if( !isset( $this->relations ) || !$this->relations ) {

			return DBH::getInstance()->create( $object, $this->table );
		}

		$db = DBH::getInstance();
		$relationData = array();

		// Find relations, and remove them from object
		foreach( $object as $key => &$item ) {

			if( isset( $this->relations[ $key ] ) ) {

				$relationData[ $key ] = array(
					
					'primary_id' => $this->relations[ $key ]['primary_id'],
					'foreign_id' => $this->relations[ $key ]['foreign_id'],
					'table' => $this->relations[ $key ]['table'],
					'data' => $item
				);

				unset( $object->$key );
			}
		}

		// Create object in database
		$id = $db->create( $object, $this->table );

		// Save relations
		foreach( $relationData as &$item ) {
				
			foreach( $item['data'] as $relation_id ) {
					
				$db->create( array(
					
				$item['primary_id'] => $id,
				$item['foreign_id'] => $relation_id
					
				), $item['table'] );
			}
		}

		unset( $object, $relationData );

		return $id;
	}

	/**
	 * Read a row from the database
	 * If any relations are given, it alse fetches the relations
	 *
	 * @param numeric $id primary_key
	 * @return object
	 */
	public function read ( $id ) {

		if( isset( $this->table ) == false ) {
				
			log::fatal( 'Table name not found', $this, 'read()' );
		}

		$db = DBH::getInstance();
	  
		if( is_numeric( $id ) == true ) {
				
			$primaryKey = $this->primary_key();
				
			$readAllSql = "`$primaryKey` = $id";
		} elseif ( is_object( $id ) || is_array( $id ) ) {
				
			$readAllSql = '';
				
			foreach( $id as $key => &$value ) {

				$readAllSql = "`$key` = '$value' AND";
			}
				
			$readAllSql = substr( $readAllSql, 0, -4 );
				
		} else {
				
			log::fatal( '$id not found', $this, 'read()' );
			return false;
		}

		$result = $db->read( $readAllSql, $this->table );

		// If no relations are set, then query object immediately
		if( !isset( $this->relations ) || !$this->relations ) {

			return $result;
		}

		return $this->extend_relations( $result );
	}

	/**
	 * Update row
	 *
	 * @todo update relations
	 *
	 * @param object $object
	 * @return bool mysql result
	 */
	public function update ( $object ) {

		if( isset( $this->table ) == false ) {
				
			log::fatal( 'Table name not found', $this, 'update()' );
		}

		if( is_object( $object ) == false || !$object ) {
				
			log::write( 'Expects and object', $this, 'update()' );
			return false;
		}

		$primaryKey = false;

		foreach( $this->model as $key => &$model ) {
				
			if( isset($model['primary']) && $model['primary'] == true ) {

				$primaryKey = $key;
				$primaryValue = $object->{$key};

				unset( $object->{$key} );

				break;
			}
		}

		if( $primaryKey == false ) {
				
			log::write( 'Trying to update, but no primary key found. ' . var_export( $object, true ), $this, 'update()' );
			return false;
		}

		return DBH::getInstance()->update( $object, "`$primaryKey` = $primaryValue", $this->table );
	}

	/**
	 * Delete a row or multible rows
	 * When arg is int, remove by primary ( from model )
	 * When arg is object, use key as field name
	 *
	 * @todo remove relations
	 *
	 * @param mixed $mixed
	 * @return void
	 */
	public function delete ( $mixed ) {

		if( isset( $this->table ) == false ) {
				
			log::fatal( 'Table name not found', $this, 'delete()' );
		}

		$db = &DBH::getInstance();

		if( is_numeric( $mixed ) == true ) {
				
			$primaryKey = $this->primary_key();
				
			$deleteWhereSql = "`$primaryKey` = $mixed";
		} elseif ( (is_object( $mixed ) == true || is_array( $mixed ) == true) && $mixed ) {
				
			$deleteWhereSql = '';
				
			foreach( $mixed as $key => $value ) {

				//var_dump( $value,  preg_match( '/^&|&$/', $value ) );

				// If in model, then add
				if( strstr( $value, '%' ) ) {
						
					$deleteWhereSql .= "`$key` LIKE '" . $db->escape( $value ) . "' AND";
				} else {
						
					$deleteWhereSql .= "`$key` = '" . $db->escape( $value ) . "' AND";
				}
			}
				
			$deleteWhereSql = substr( $deleteWhereSql, 0, strlen($deleteWhereSql) - 4 );
				
		} else {
				
			log::write( 'No valid variable given or empty var. ' . var_export( $mixed, true ), $this, 'delete()' );
			return false;
		}

		return $db->delete( $deleteWhereSql, $this->table );
	}

	/**
	 * Read entire table
	 *
	 * @todo Add order by, read relations
	 *
	 * @return void
	 */
	public function read_all() {

		if( isset( $this->table ) == false ) {
				
			log::fatal( 'Table name not found', $this, 'read_all()' );
			return false;
		}

		return DBH::getInstance()->read_all( $this->table );
	}

	/**
	 * Read all rows in table where ..
	 *
	 * @param object $object where clause
	 * @return object
	 */
	public function read_all_where ( $object ) {

		if( isset( $this->table ) == false ) {
				
			log::fatal( 'Table name not found', $this, 'read_all_where()' );
			return false;
		}

		return DBH::getInstance()->read_all_where( $object, $this->table );
	}

	/**
	 * Read entire table and relations
	 *
	 * @todo Add order by, offset 0, 10
	 *
	 * @return void
	 */
	public function read_all_with_relations() {

		if( isset( $this->table ) == false ) {
				
			log::fatal( 'Table name not found', $this, 'read_all()' );
			return false;
		}

		$db = DBH::getInstance();

		$result = $db->query("SELECT * FROM `{$this->table}`");

		if( !$result ) {
			 
			return false;
		}

		// If no relations are set, then query object immediately
		if( !isset( $this->relations ) || !$this->relations ) {

			return $result;
		}

		$all_result = array();

		while( $row = mysql_fetch_object($result) ) {
			 
			$all_result[] = $this->extend_relations( $row );
		}

		return $all_result;
	}

	/**
	 * Get relation by row object
	 *
	 * @param numeric $id row id
	 * @return object relations and ids
	 */
	public function extend_relations ( &$object ) {

		if( isset( $this->table ) == false ) {
				
			log::fatal( 'Table name not found', $this, 'read_relation()' );
		}

		if( is_object( $object ) == false ) {
				
			log::write( 'Expects an object', $this, 'read_relation()' );
			return false;
		}

		$db = DBH::getInstance();
		$primaryKey = $this->primary_key();

		foreach( $this->relations as $key => &$relation ) {
				
			$object->$key = $db->result_field( $db->read_all_where( array(

			$relation['primary_id'] => $object->$primaryKey
			), $relation['table'] ), $relation['foreign_id'] );
		}

		return $object;
	}

	/**
	 * Get the primary key from
	 * Returns false if primary_key isn`t found
	 *
	 * @return string Primary_key name
	 */
	public function primary_key () {

		foreach( $this->model as $key => &$model ) {
				
			if( isset($model['primary']) && $model['primary'] == true ) {

				return $key;
			}
		}

		log::write('Primary key not found', $this, 'primary_key()');

		return false;
	}

	/*
	 * Delete a file on the server
	* @param String filename
	* @param boolean subStr
	* @param boolean addslash
	* @return boolean true, false
	*/
	public function deleteFile($filename, $subStr, $addslash){
			
		$fileUrl = $_SERVER['DOCUMENT_ROOT'].$this->view->baseUrl(); // get the server root and baseUrl of the site
		if($addslash == true){
			$fileUrl .= DIRSEP;
		}
		if($subStr == true){
			$fileSubstr = substr($filename, 2); // strip the .. at the fron of the string
			$fileUrl .= $fileSubstr; //add file location to baseurl
		}else{
			$fileUrl .= $filename;
		}
		if(!file_exists($fileUrl)){
			log::write('Could not find the file', $this, 'deleteFile()');
			return;
		}
		if(!is_writable($fileUrl)){
			if(!chown($fileUrl, "nobody")){
				log::write('File could not be chown', $this, 'deleteFile() line 417');
				return;
			}
			if(!chmod($fileUrl, 0755)){
				log::write('File could not be chmod', $this, 'deleteFile() line 421');
				return;
			}
		}
		if(!unlink($fileUrl)){
			log::write('File could not be delete', $this, 'deleteFile() line 426');
			return;
		}
	}

	//Function to sanitize values received from the form. Prevents SQL injection
	public function clean($str) {
		$str = @trim($str);
		if(get_magic_quotes_gpc()) {
			$str = stripslashes($str);
		}
		return @mysql_real_escape_string($str);
	}


	/*
	 * Check file type
	* @param String $file
	* @return String $file_type
	*/
	public function findFileExtention($file){
		if($file == "image/gif"){
			return $file_type = ".gif";
		}elseif(($file == "image/pjepg") || ($file == "image/jpeg") || ($file == "image/jpg")){
			return $file_type = ".jpg";
		}elseif(($file == "image/x-png") || ($file == "image/png")){
			return $file_type = ".png";
		}else{
			$file_type = explode('.', $file);
			return '.'.$file_type[1];
		}
	}

	public function IsLoggedin(){
		$loggedin = $_SESSION['loggedin']; // Are they loggedin?

		// They are not logged in, Kill the page and ask them to login.
		if ($loggedin != "true") {
			die('Sorry your not loggedin, Click <a href="/login?logout=false"> Here </a> to login');
		}
	}

	 
	function curPageName() {
		return substr($_SERVER["SCRIPT_NAME"],strrpos($_SERVER["SCRIPT_NAME"],"/")+1);
	}

	public function getPageContent(){	
		
		$aParameters = explode("/", $this->selfURL());
		//var_dump(end($aParameters));
    	$whereClause = "url = '".strtolower(end($aParameters))."'";
    	$result = DBH::getInstance()->read($whereClause, 'page');
    	$this->view->page_content = $result;
    }

	public function selfURL() {
			$s = empty($_SERVER["HTTPS"]) ? ''
				: ($_SERVER["HTTPS"] == "on") ? "s"
				: "";
			$protocol = $this->strleft(strtolower($_SERVER["SERVER_PROTOCOL"]), "/").$s;
			$port = ($_SERVER["SERVER_PORT"] == "80") ? ""
				: (":".$_SERVER["SERVER_PORT"]);
			return $protocol."://".$_SERVER['SERVER_NAME'].$port.$_SERVER['REQUEST_URI'];
		}
		
	public function strleft($s1, $s2) {
			return substr($s1, 0, strpos($s1, $s2));
		}
}